package cn.knight.basic.service.impl;

import cn.knight.basic.constant.BaseConstants;
import cn.knight.basic.exception.BusinessException;
import cn.knight.basic.service.IVerifyCodeService;
import cn.knight.basic.utils.SmsUtils;
import cn.knight.basic.utils.StrUtils;
import cn.knight.basic.utils.VerifyCodeUtils;
import cn.knight.basic.vo.RegisterVo;
import cn.knight.user.domain.User;
import cn.knight.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    /**
    * @Title: graph
    * @Description: 用户注册图形验证码
    * @Author: winnie
    * @Version: 1.0
    * @Date:  7/7/2022 下午11:44
    * @Parameters: [imageCodeKey]
    * @Return java.lang.String
    */
    @Override
    public String graph(String imageCodeKey) {
        // 判断前端传递的uuid是否为空
        if (StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("参数错误，请正确传递参数");
        }

        // 使用工具类生成随机四位字符串
        String code = StrUtils.getComplexRandomString(4);

        // 根据前端传递的UUID作为key，将code存入到redis中
        redisTemplate.opsForValue().set(imageCodeKey, code, 5, TimeUnit.MINUTES);

        // 使用2D技术工具类，将code存入图片中，并返回
        String base64Str = VerifyCodeUtils.VerifyCode(100, 30, code);

        return base64Str;
    }

    /**
    * @Title: smsCode
    * @Description: 用户注册短信验证码
    * @Author: winnie
    * @Version: 1.0
    * @Date:  7/7/2022 下午11:45
    * @Parameters: [vo]
    * @Return void
    */
    @Override
    public void smsCode(RegisterVo registerVo) {
        String phone = registerVo.getPhone();
        String type = registerVo.getType();


        // 非空检验
        if (StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(type)){
            throw new BusinessException("参数不能为空！");
        }

        // 根据type来判断是什么业务
        if ("register".equals(type)){
            // 调用校验图形验证码方法，校验图形验证码
            CheckImageCode(registerVo);

            // 用户是否已注册
            User user = userMapper.loadByPhone(phone);
            if (user != null){
                throw new BusinessException("用户已存在，请直接登录");
            }
            // 调用发送验证码方法，发送验证码
            SendCode(BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX, phone);
        } else if ("binder".equals(type)){
            SendCode(BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_PREFIX, phone);
        }


    }




    /**
    * @Title: settledsmsCode
    * @Description: 店铺入驻短信验证码
    * @Author: winnie
    * @Version: 1.0
    * @Date:  8/7/2022 上午12:55
    * @Parameters: [phone]
    * @Return void
    */
    @Override
    public void settledsmsCode(String phone) {
        // 非空校验
        if (StringUtils.isEmpty(phone)){
            throw new BusinessException("手机号不能为空，请重新输入");
        }

        // 用户是否已注册
        User user = userMapper.loadByPhone(phone);
        if (user != null){
            throw new BusinessException("用户已存在，请直接登录");
        }

        // 根据业务键+phone作为key在redis中获取value
        String shopsettledCodeKey= BaseConstants.VerifyCodeConstant.BUSINESS_SHOPSETTLED_PREFIX+ phone;
        Object shopsettledCodeValue = redisTemplate.opsForValue().get(shopsettledCodeKey);

        // 生成一个空字符串，存放发送短信时的验证码对象
        String phoneCode = "";
        // 判断获取到的value对象是否存在
        if (shopsettledCodeValue == null){
            // 不存在
            // 生成一个随机4位验证码
            phoneCode = StrUtils.getComplexRandomString(4);
        } else {
            // 存在
            // 将value的值根据":"进行分割
            String[] phoneCodeValueTmp = shopsettledCodeValue.toString().split(":");

            // 获取到旧的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 获取到新的时间戳
            Long nowTime = System.currentTimeMillis();
            // 对时间戳做减法，判断是否大于1分钟
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟后再获取");
            }
            phoneCode = phoneCodeValueTmp[1];

        }
        // 拼接上时间戳后，根据上面的key，存入到redis中
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(shopsettledCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);

        // 发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);

    }

    /**
    * @Title: CheckImageCode
    * @Description: 校验图形验证码
    * @Author: winnie
    * @Version: 1.0
    * @Date:  2022/7/10 18:33
    * @Parameters: [registerVo]
    * @Return void
    */
    private void CheckImageCode(RegisterVo registerVo) {
        String imageCodeValue = registerVo.getImageCodeValue();
        String imageCodeKey = registerVo.getImageCodeKey();
        // 校验图形验证码信息
        Object imageTempCode = redisTemplate.opsForValue().get(imageCodeKey);
        // 图形验证码不存在
        if (imageTempCode == null){
            throw new BusinessException("图形验证码已过期，请重新获取图形验证码");
        }
        // 图形验证码错误
        if (!imageTempCode.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("请正确填写图形验证码");
        }
    }

    /**
    * @Title: SendCode
    * @Description: 生成手机验证码
    * @Author: winnie
    * @Version: 1.0
    * @Date:  2022/7/10 18:41
    * @Parameters: [businessKey, phone]
    * @Return void
    */
    private void SendCode(String businessKey, String phone) {
        // 根据业务键+phone作为key在redis中获取value
        String phoneCodeKey= businessKey + phone;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);

        // 生成一个空字符串，存放发送短信时的验证码对象
        String phoneCode = "";
        // 判断获取到的value对象是否存在
        if (phoneCodeValue == null){
            // 不存在
            // 生成一个随机4位验证码
            phoneCode = StrUtils.getComplexRandomString(4);
        } else {
            // 存在
            // 将value的值根据":"进行分割
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");

            // 获取到旧的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 获取到新的时间戳
            Long nowTime = System.currentTimeMillis();
            // 对时间戳做减法，判断是否大于1分钟
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟后再获取");
            }
            phoneCode = phoneCodeValueTmp[1];

        }
        // 拼接上时间戳后，根据上面的key，存入到redis中
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);

        // 发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);
    }
}
